package com.yungu.swift.order.service.impl;

import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.dubbo.config.annotation.Service;
import com.yungu.swift.assets.driver.service.DriverService;
import com.yungu.swift.assets.passenger.model.vo.PassengerVo;
import com.yungu.swift.assets.passenger.service.PassengerService;
import com.yungu.swift.base.ResponseData;
import com.yungu.swift.constants.OrderConstant;
import com.yungu.swift.order.helper.OrderHelper;
import com.yungu.swift.order.model.dto.OrderDetailDto;
import com.yungu.swift.order.model.dto.OrderDto;
import com.yungu.swift.order.model.dto.OrderFareDto;
import com.yungu.swift.order.model.param.RefundParam;
import com.yungu.swift.order.model.vo.RefundVo;
import com.yungu.swift.order.service.OrderFareService;
import com.yungu.swift.order.service.OrderService;
import com.yungu.swift.order.service.RefundService;
import com.yungu.swift.order.utils.RefundDataBuilder;
import com.yungu.swift.order.utils.SendMessageUtils;
import com.yungu.swift.socket.push.model.PushContent;
import com.yungu.swift.socket.push.service.PushService;
import com.yungu.swift.system.finance.model.dto.FinanceJoinRefundDto;
import com.yungu.swift.system.finance.model.dto.FinanceOrderDto;
import com.yungu.swift.system.finance.model.dto.FinancePrepayDto;
import com.yungu.swift.system.finance.model.dto.FinanceRefundDto;
import com.yungu.swift.system.finance.service.FinanceJoinRefundService;
import com.yungu.swift.system.finance.service.FinanceOrderService;
import com.yungu.swift.system.finance.service.FinancePrepayService;
import com.yungu.swift.system.finance.service.FinanceRefundService;
import com.yungu.swift.system.sys.model.dto.*;
import com.yungu.swift.system.sys.service.*;
import com.yungu.swift.utils.DateUtils;
import com.yungu.swift.utils.MapUtils;
import com.yungu.swift.utils.ParamUtil;
import com.yungu.swift.utils.StringUtils;
import org.apache.commons.collections4.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import java.math.BigDecimal;
import java.util.*;

import static com.yungu.swift.constants.FinanceConstant.*;

@Service
public class RefundServiceImpl implements RefundService {

    private static final Logger logger = LoggerFactory.getLogger(RefundServiceImpl.class);

    private static final String EXT_PAY_TRADE_NO = "EXT";

    @Autowired
    private OrderService orderService;
    @Autowired
    private OrderFareService orderFareService;
    @Reference
    private PassengerService passengerService;
    @Reference
    private FinanceJoinRefundService financeJoinRefundService;
    @Reference
    private FinanceRefundService financeRefundService;
    @Reference
    private FinancePrepayService financePrepayService;
    @Reference
    private FinanceOrderService financeOrderService;
    @Reference
    private SysAccountPlatformService sysAccountPlatformService;
    @Reference
    private SysAccountAgentService sysAccountAgentService;
    @Reference
    private SysAccountCompanyService sysAccountCompanyService;
    @Reference
    private SysAccountPassengerService sysAccountPassengerService;
    @Reference
    private SysAccountDriverService sysAccountDriverService;
    @Reference
    private DriverService driverService;
    @Reference
    private PushService pushService;


    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResponseData<Integer> refund(RefundParam refundParam) {
        Long count = financeJoinRefundService.countByOrderUuid(refundParam.getOrderUuid()).getData();
        if (count != null && count > 0) {
            return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "请勿重复提交退款请求");
        }
        RefundVo refundVo = buildRefundVo(refundParam);
        int status = FinanceJoinRefundDto.STATUS_REFUND;
        String refundNo = "";
        try {
            // 0 元退款处理 —— 账户没有变动 —— 有退款原因也记录一份退款申请
            if (refundVo.getRefundFare() == 0) {
                saveFinanceJoinRefundDto(refundVo, FinanceJoinRefundDto.STATUS_SUCCESS, refundNo);
                orderHandle(refundVo.getOrderUuid(), refundVo.getRefundFare(), true, true);
                return ResponseData.buildSuccessResponse("退款请求成功", FinanceJoinRefundDto.STATUS_SUCCESS);
            }
            // 外部订单退款
            if (EXT_PAY_TRADE_NO.equals(refundVo.getPayTradeNo()) && refundCalculation(refundVo)) {
                //写资金退款申请表
                saveFinanceJoinRefundDto(refundVo, FinanceJoinRefundDto.STATUS_SUCCESS, refundNo);
                // 处理退款后逻辑
                orderHandle(refundVo.getOrderUuid(), refundVo.getRefundFare(), true, false);
                return ResponseData.buildSuccessResponse("退款请求成功", FinanceJoinRefundDto.STATUS_SUCCESS);
            }
            //系统余额退款
            if (OrderConstant.PAY_TYPE_BALANCE == refundVo.getType() && refundCalculation(refundVo)) {
                status = FinanceJoinRefundDto.STATUS_SUCCESS;
            }
            //微信退款
            if (OrderConstant.PAY_TYPE_TENPAY == refundVo.getType()) {
                ResponseData<String> responseData = RefundDataBuilder.buildWxRefundData(refundVo);
                if (responseData.isSuccess() && StringUtils.isNotEmpty(responseData.getData())) {
                    refundNo = responseData.getData();
                    status = FinanceJoinRefundDto.STATUS_REFUND;
                    //先退款 在把分润的钱收到平台-写退款流水
                    refundCalculation(refundVo);
                }

            }
            //支付宝退款
            if (OrderConstant.PAY_TYPE_ALIPAY == refundVo.getType()) {
                ResponseData<String> responseData = RefundDataBuilder.buildAliRefundData(refundVo);
                if (responseData.isSuccess() && StringUtils.isNotEmpty(responseData.getData())) {
                    refundNo = responseData.getData();
                    status = FinanceJoinRefundDto.STATUS_REFUND;
                    //先退款 在把分润的钱收到平台-写退款流水
                    refundCalculation(refundVo);
                }
            }
            //写资金退款记录表
            saveFinanceJoinRefundDto(refundVo, status, refundNo);
            // 处理退款后逻辑
            orderHandle(refundVo.getOrderUuid(), refundVo.getRefundFare(), status == FinanceJoinRefundDto.STATUS_SUCCESS, true);
        } catch (RefundException e) {
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            logger.error("订单：{}，退款出现异常，回滚退款操作", refundVo.getOrderUuid(), e);
            return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "退款异常");
        }
        return ResponseData.buildSuccessResponse("退款请求成功", status);
    }

    /**
     * 构建 RefundVo 实体
     *
     * @param refundParam
     * @return
     */
    private RefundVo buildRefundVo(RefundParam refundParam) {
        RefundVo refundVo = new RefundVo();
        //生成商户订单号
        refundVo.setFinanceRefundUuid(StringUtils.buildUUID());
        refundVo.setTradeNo(StringUtils.buildUUID().toUpperCase());
        refundVo.setRefundFare(refundParam.getRefundFare());
        OrderDto orderDto = orderService.get(refundParam.getOrderUuid()).getData();
        if (orderDto != null) {
            refundVo.setAppid(orderDto.getAppid());
            refundVo.setOrderUuid(orderDto.getUuid());
            refundVo.setPassengerUuid(orderDto.getPassengerUuid());
            refundVo.setType(orderDto.getPayType());
            refundVo.setCreateBy(ParamUtil.defaultIfNull(refundParam.getCreateBy(), orderDto.getPassengerUuid()));
            refundVo.setPayTradeNo(orderDto.getSource() == OrderConstant.ORDER_SOURCE_EXTERNAL ? EXT_PAY_TRADE_NO : null);
        }
        if (refundVo.getPayTradeNo() == null) {
            Map<String, Object> build = MapUtils.build("orderUuid", refundParam.getOrderUuid());
            List<FinancePrepayDto> prepayDtoList = financePrepayService.list(build).getData();
            if (CollectionUtils.isNotEmpty(prepayDtoList)) {
                refundVo.setPayTradeNo(prepayDtoList.get(0).getSerialNumber());
            } else {
                refundVo.setPayTradeNo("BALANCE");
            }
        }
        OrderFareDto orderFareDto = orderFareService.findByOrderUuid(refundParam.getOrderUuid()).getData();
        if (null != orderFareDto) {
            //实际支付金额
            refundVo.setActualFare(orderFareDto.getActualFare());
            if (refundVo.getRefundFare() == null) {
                //退款金额考虑优惠券抵扣的情况
                double refundFare = orderFareDto.getActualFare() - refundParam.getPayFare();
                if (refundFare < 0) {
                    refundFare = 0.0;
                }
                refundVo.setRefundFare(refundFare);
            }
        }
        return refundVo;
    }

    /**
     * 获取退款记录表实体类
     *
     * @param refundVo
     * @param status
     * @param refundNo
     * @return
     */
    private void saveFinanceJoinRefundDto(RefundVo refundVo, Integer status, String refundNo) throws RefundException {
        FinanceJoinRefundDto financeJoinRefundDto = new FinanceJoinRefundDto();
        financeJoinRefundDto.setUuid(refundVo.getFinanceRefundUuid());
        financeJoinRefundDto.setAppid(refundVo.getAppid());
        financeJoinRefundDto.setOrderUuid(refundVo.getOrderUuid());
        financeJoinRefundDto.setPayTradeNo(refundVo.getPayTradeNo());
        financeJoinRefundDto.setTradeNo(refundVo.getTradeNo());
        financeJoinRefundDto.setRefundNo(refundNo);
        financeJoinRefundDto.setType(refundVo.getType());
        financeJoinRefundDto.setMoney(refundVo.getRefundFare().doubleValue());
        financeJoinRefundDto.setRemark(refundVo.getRemark());
        financeJoinRefundDto.setCreateOn(new Date());
        financeJoinRefundDto.setUpdateOn(new Date());
        financeJoinRefundDto.setCreateBy(refundVo.getCreateBy());
        financeJoinRefundDto.setUpdateBy(refundVo.getCreateBy());
        financeJoinRefundDto.setParams(refundVo.toString());
        financeJoinRefundDto.setStatus(status);
        ResponseData<Boolean> add = financeJoinRefundService.add(financeJoinRefundDto);
        if (!add.isSuccess() || add.getData() == null || Objects.equals(add.getData(), Boolean.FALSE)) {
            throw new RefundException();
        }
    }

    /**
     * 退款操作
     *
     * @return 退款单号
     */
    private Boolean refundCalculation(RefundVo refundVo) throws RefundException {
        Map<String, Object> map = MapUtils.build("orderUuid", refundVo.getOrderUuid());
        // 1. 平台账户
        ResponseData<SysAccountPlatformDto> getAccountPlatform = sysAccountPlatformService.getByAppid(refundVo.getAppid());
        if (!getAccountPlatform.isSuccess() || getAccountPlatform.getData() == null) {
            logger.warn("获取平台账户出错，appid：{}", refundVo.getAppid());
            return false;
        }
        SysAccountPlatformDto accountPlatformDto = getAccountPlatform.getData();
        // 2. 订单信息
        OrderDto orderDto = orderService.get(refundVo.getOrderUuid()).getData();
        if (orderDto == null) {
            logger.warn("获取订单信息出错, orderUuid:{}", refundVo.getOrderUuid());
            return false;
        }
        // 3.司机账户
        ResponseData<SysAccountDriverDto> getDriverAccount = sysAccountDriverService.get(orderDto.getActualDriverUuid());
        if (!getDriverAccount.isSuccess() || getDriverAccount.getData() == null) {
            logger.warn("获取司机账户出错，driverUuid：{}", orderDto.getActualDriverUuid());
            return false;
        }
        SysAccountDriverDto accountDriverDto = getDriverAccount.getData();
        // 4、代理和企业账户
        SysAccountAgentDto accountAgentDto = null;
        map.put("course", AGENT_EXTRACT);
        FinanceOrderDto agentFinanceOrder = financeOrderService.get(map).getData();
        if (agentFinanceOrder != null) {
            accountAgentDto = sysAccountAgentService.get(agentFinanceOrder.getFinanceInflow()).getData();
        }
        SysAccountCompanyDto accountCompanyDto = null;
        map.put("course", COMPANY_EXTRACT);
        FinanceOrderDto companyFinanceOrder = financeOrderService.get(map).getData();
        if (companyFinanceOrder != null) {
            accountCompanyDto = sysAccountCompanyService.get(companyFinanceOrder.getFinanceInflow()).getData();
        }
        // 退款 —— 根据订单判断平台，代理，企业，司机是否有抽成流水，有抽成则统一退回到平台
        logger.info("订单：{}， 退款开始", refundVo.getOrderUuid());
        // 1-1 平台附加费退款（全额退款的时候才退附加费）
        BigDecimal addFee = BigDecimal.ZERO;
        map.put("course", DRIVER_ADDITIONAL_FEE);
        FinanceOrderDto addFeeFinanceOrder = financeOrderService.get(map).getData();
        if (addFeeFinanceOrder != null && refundVo.getRefundFare() > 0 && refundVo.getRefundFare() < refundVo.getActualFare()) {
            addFee = addFeeFinanceOrder.getAmount();
        }
        if (addFeeFinanceOrder != null && refundVo.getRefundFare() > 0 && refundVo.getRefundFare().equals(refundVo.getActualFare())) {
            BigDecimal amount = addFeeFinanceOrder.getAmount();
            BigDecimal frozenBalance = accountDriverDto.getFrozenBalance().add(amount);
            String description = "平台附加费退款" + amount + "元到司机";
            saveFinanceRefundDto(refundVo, accountDriverDto.getUuid(), accountPlatformDto.getUuid(), amount, ADD_FEE_REFUND,
                    description, accountDriverDto.getFrozenBalance(), frozenBalance);
            accountDriverDto.setFrozenBalance(frozenBalance);
            accountPlatformDto.setCashBalance(accountPlatformDto.getCashBalance().subtract(amount));
            logger.info("订单：{} - {}", refundVo.getOrderUuid(), description);
        }
        // 退款比例
        BigDecimal refundScale = BigDecimal.valueOf(1.00);
        BigDecimal actualRefundFare = BigDecimal.valueOf(refundVo.getRefundFare());
        // 部分退款
        if (refundVo.getRefundFare() < refundVo.getActualFare() && refundVo.getRefundFare() > 0) {
            refundScale = actualRefundFare.divide(BigDecimal.valueOf(refundVo.getActualFare()).subtract(addFee), 4, BigDecimal.ROUND_HALF_UP);
        }
        //设置退款描述
        String refundDescibe = "";
        if (refundScale.compareTo(BigDecimal.ONE) != 0) {
            refundDescibe = "部分";
        }
        logger.info("订单：{}， 退款比例：{}", refundVo.getOrderUuid(), refundScale.toString());
        // 1-2 平台分润退款 只记录平台退款流水 账户信息不用改变
        map.put("course", PLATFORM_EXTRACT);
        FinanceOrderDto platformFinanceOrder = financeOrderService.get(map).getData();
        if (platformFinanceOrder != null) {
//            BigDecimal multiply = platformFinanceOrder.getAmount().multiply(refundScale).setScale(1, BigDecimal.ROUND_HALF_UP);
            BigDecimal multiply = platformFinanceOrder.getAmount().multiply(refundScale).setScale(2, BigDecimal.ROUND_HALF_UP);
            int course = refundScale.compareTo(BigDecimal.ONE) == 0 ? PLATFORM_EXTRACT_REFUND : PLATFORM_PART_EXTRACT_REFUND;
            String description = "平台分润" + refundDescibe + "退款 " + multiply + "元到平台";
            saveFinanceRefundDto(refundVo, accountPlatformDto.getUuid(), "", multiply, course,
                    description, accountPlatformDto.getCashBalance(), accountPlatformDto.getCashBalance());
            logger.info("订单：{} - {}", refundVo.getOrderUuid(), description);
            actualRefundFare = actualRefundFare.subtract(multiply);
        }
        // 4-1 公司分润退款
        if (companyFinanceOrder != null && accountCompanyDto != null) {
            // 记录流水 -公司现金金额 +平台现金金额
//            BigDecimal multiply = companyFinanceOrder.getAmount().multiply(refundScale).setScale(1, BigDecimal.ROUND_HALF_UP);
            BigDecimal multiply = companyFinanceOrder.getAmount().multiply(refundScale).setScale(2, BigDecimal.ROUND_HALF_UP);
            BigDecimal cashBalance = accountCompanyDto.getCashBalance().subtract(multiply);
            int course = refundScale.compareTo(BigDecimal.ONE) == 0 ? COMPANY_EXTRACT_REFUND : COMPANY_PART_EXTRACT_REFUND;
            String description = "企业分润" + refundDescibe + "退款" + multiply + "元到平台";
            saveFinanceRefundDto(refundVo, accountPlatformDto.getUuid(), accountCompanyDto.getUuid(), multiply, course,
                    description, accountCompanyDto.getCashBalance(), cashBalance);
            accountCompanyDto.setCashBalance(cashBalance);
            accountPlatformDto.setCashBalance(accountPlatformDto.getCashBalance().add(multiply));
            logger.info("订单：{} - {}", refundVo.getOrderUuid(), description);
            actualRefundFare = actualRefundFare.subtract(multiply);
        } else {
            logger.warn("订单：{} 公司分润退款不执行，获取不到抽成流水或司机账户为空", refundVo.getOrderUuid());
        }
        // 4-2 代理分润退款
        if (agentFinanceOrder != null && accountAgentDto != null) {
            // 记录流水 -代理现金金额 +平台现金金额
//            BigDecimal multiply = agentFinanceOrder.getAmount().multiply(refundScale).setScale(1, BigDecimal.ROUND_HALF_UP);
            BigDecimal multiply = agentFinanceOrder.getAmount().multiply(refundScale).setScale(2, BigDecimal.ROUND_HALF_UP);
            BigDecimal cashBalance = accountAgentDto.getCashBalance().subtract(multiply);
            int course = refundScale.compareTo(BigDecimal.ONE) == 0 ? AGENT_EXTRACT_REFUND : AGENT_PART_EXTRACT_REFUND;
            String description = "企业分润" + refundDescibe + "退款" + multiply + "元到平台";
            saveFinanceRefundDto(refundVo, accountPlatformDto.getUuid(), accountAgentDto.getUuid(), multiply,
                    course, description, accountAgentDto.getCashBalance(), accountAgentDto.getCashBalance().subtract(multiply));
            accountAgentDto.setCashBalance(cashBalance);
            accountPlatformDto.setCashBalance(accountPlatformDto.getCashBalance().add(multiply));
            logger.info("订单：{} - {}", refundVo.getOrderUuid(), description);
            actualRefundFare = actualRefundFare.subtract(multiply);
        } else {
            logger.warn("订单：{} 代理分润退款不执行，获取不到抽成流水或司机账户为空", refundVo.getOrderUuid());
        }

        // 3-1 司机分润退款
        map.put("course", DRIVER_EXTRACT);
        FinanceOrderDto driverFinanceOrder = financeOrderService.get(map).getData();
        if (driverFinanceOrder != null) {
            // 记录流水 -司机冻结金额 +平台现金金额
//            actualRefundFare = actualRefundFare.setScale(1, BigDecimal.ROUND_HALF_UP);
            actualRefundFare = actualRefundFare.setScale(2, BigDecimal.ROUND_HALF_UP);
            BigDecimal frozenBalance = accountDriverDto.getFrozenBalance().subtract(actualRefundFare);
            int course = refundScale.compareTo(BigDecimal.ONE) == 0 ? DRIVER_EXTRACT_REFUND : DRIVER_PART_EXTRACT_REFUND;
            String description = "司机分润" + refundDescibe + "退款" + actualRefundFare + "元到平台";
            saveFinanceRefundDto(refundVo, accountPlatformDto.getUuid(), accountDriverDto.getUuid(), actualRefundFare, course,
                    description, accountDriverDto.getFrozenBalance(), frozenBalance);
            accountDriverDto.setFrozenBalance(frozenBalance);
            accountPlatformDto.setCashBalance(accountPlatformDto.getCashBalance().add(actualRefundFare));
            logger.info("订单：{} - {}", refundVo.getOrderUuid(), description);
        }

        // 更新账户信息
        if (accountDriverDto != null) {
            sysAccountDriverService.edit(accountDriverDto);
        }
        if (accountCompanyDto != null) {
            sysAccountCompanyService.edit(accountCompanyDto);
        }
        if (accountAgentDto != null) {
            sysAccountAgentService.edit(accountAgentDto);
        }

        // 处理乘客账户
        handlePasAccount(refundVo, accountPlatformDto);

        // 更新平台账户信息
        sysAccountPlatformService.edit(accountPlatformDto);

        logger.info("订单：{}， 退款流程结束", refundVo.getOrderUuid());
        return Boolean.TRUE;
    }


    /**
     * 退款中的乘客部分
     *
     * @param refundVo           退款参数
     * @param accountPlatformDto 平台账户
     * @throws RefundException
     */
    private void handlePasAccount(RefundVo refundVo, SysAccountPlatformDto accountPlatformDto) throws RefundException {
        // 退款比例
        BigDecimal refundScale = BigDecimal.valueOf(1.00);
        // 部分退款
        if (refundVo.getRefundFare() < refundVo.getActualFare() && refundVo.getRefundFare() > 0) {
            refundScale = BigDecimal.valueOf(refundVo.getRefundFare()).divide(
                    BigDecimal.valueOf(refundVo.getActualFare()), 4, BigDecimal.ROUND_HALF_UP);
        }
        //设置退款描述
        String refundDescibe = "";
        if (refundScale.compareTo(BigDecimal.ONE) != 0) {
            refundDescibe = "部分";
        }

        // 外部支付不处理乘客账户
        if (EXT_PAY_TRADE_NO.equals(refundVo.getPayTradeNo())) {
            logger.info("订单：{} - {}", refundVo.getOrderUuid(), "外部支付不处理乘客账户");
            return;
        }
        Map<String, Object> map = MapUtils.build("orderUuid", refundVo.getOrderUuid());
        // 1. 乘客账户
        ResponseData<SysAccountPassengerDto> getAccountPas = sysAccountPassengerService.get(refundVo.getPassengerUuid());
        if (!getAccountPas.isSuccess() || getAccountPas.getData() == null) {
            logger.warn("获取乘客账户出错，pasUuid：{}", refundVo.getPassengerUuid());
            return;
        }
        SysAccountPassengerDto accountPasDto = getAccountPas.getData();

        // 1-1 是否有使用优惠券 增加优惠券退款流水 修改平台账户优惠券累积
        map.put("course", MARKET_PART_PAY);
        FinanceOrderDto marketingFinanceOrder = financeOrderService.get(map).getData();
        if (marketingFinanceOrder != null) {
//            BigDecimal multiply = marketingFinanceOrder.getAmount().multiply(refundScale).setScale(1, BigDecimal.ROUND_HALF_UP);
            BigDecimal multiply = marketingFinanceOrder.getAmount().multiply(refundScale).setScale(2, BigDecimal.ROUND_HALF_UP);
            BigDecimal couponAccumulate = accountPlatformDto.getCouponAccumulate().subtract(multiply);
            int course = refundScale.compareTo(BigDecimal.ONE) == 0 ? MARKET_REFUND : MARKET_PART_REFUND;
            String description = "优惠券" + refundDescibe + "退款" + multiply + "元到平台";
            saveFinanceRefundDto(refundVo, accountPlatformDto.getUuid(), accountPlatformDto.getUuid(), multiply, course,
                    description, accountPlatformDto.getCouponAccumulate(), couponAccumulate);
            accountPlatformDto.setCouponAccumulate(couponAccumulate);
            logger.info("订单：{} - {}", refundVo.getOrderUuid(), description);
        }
        // 1-2 退回乘客充值余额
        map.put("course", PASSENGER_RECHARGE_BALANCE_PAY);
        FinanceOrderDto rechargeFinanceOrderDto = financeOrderService.get(map).getData();
        if (rechargeFinanceOrderDto != null) {
            // + 乘客充值余额
//            BigDecimal multiply = rechargeFinanceOrderDto.getAmount().multiply(refundScale).setScale(1, BigDecimal.ROUND_HALF_UP);
            BigDecimal multiply = rechargeFinanceOrderDto.getAmount().multiply(refundScale).setScale(2, BigDecimal.ROUND_HALF_UP);
            BigDecimal rechargeBalance = accountPasDto.getRechargeBalance().add(multiply);
            //判断全额或者部分
            int course = refundScale.compareTo(BigDecimal.ONE) == 0 ? PLATFORM_REFUND_TO_PASSENGER_RECHARGE : PLATFORM_PART_REFUND_TO_PASSENGER_RECHARGE;
            String description = "订单" + refundDescibe + "退款" + multiply + "元到乘客充值余额";
            saveFinanceRefundDto(refundVo, accountPasDto.getUuid(), "", multiply, course,
                    description, accountPasDto.getRechargeBalance(), rechargeBalance);
            accountPasDto.setRechargeBalance(rechargeBalance);
            logger.info("订单：{} - {}", refundVo.getOrderUuid(), description);
        }
        // 1-3 退回到乘客赠送余额
        map.put("course", PASSENGER_PRESENT_BALANCE_PAY);
        FinanceOrderDto presentFinanceOrderDto = financeOrderService.get(map).getData();
        if (presentFinanceOrderDto != null) {
            // + 乘客赠送余额
//            BigDecimal multiply = presentFinanceOrderDto.getAmount().multiply(refundScale).setScale(1, BigDecimal.ROUND_HALF_UP);
            BigDecimal multiply = presentFinanceOrderDto.getAmount().multiply(refundScale).setScale(2, BigDecimal.ROUND_HALF_UP);
            BigDecimal presentBalance = accountPasDto.getPresentBalance().add(multiply);
            //判断全额或者部分
            int course = refundScale.compareTo(BigDecimal.ONE) == 0 ? PLATFORM_REFUND_TO_PASSENGER_PRESENT : PLATFORM_PART_REFUND_TO_PASSENGER_PRESENT;
            String description = "订单" + refundDescibe + "退款" + multiply + "元到乘客赠送余额";
            saveFinanceRefundDto(refundVo, accountPasDto.getUuid(), "", multiply,
                    course, description, accountPasDto.getPresentBalance(), presentBalance);
            accountPasDto.setPresentBalance(presentBalance);
            logger.info("订单：{} - {}", refundVo.getOrderUuid(), description);
        }
        // 1-4 退到微信
        map.put("course", PASSENGER_TEN_PAY);
        FinanceOrderDto weChatPayFinanceOrderDto = financeOrderService.get(map).getData();
        if (weChatPayFinanceOrderDto != null) {
            // - 乘客微信累积
//            BigDecimal multiply = weChatPayFinanceOrderDto.getAmount().multiply(refundScale).setScale(1, BigDecimal.ROUND_HALF_UP);
            BigDecimal multiply = weChatPayFinanceOrderDto.getAmount().multiply(refundScale).setScale(2, BigDecimal.ROUND_HALF_UP);
            //判断全额或者部分
            int course = refundScale.compareTo(BigDecimal.ONE) == 0 ? PLATFORM_REFUND_TO_PASSENGER_TENPAY : PLATFORM_PART_REFUND_TO_PASSENGER_TENPAY;
            String description = "订单" + refundDescibe + "退款" + multiply + "元到乘客微信账户";
            BigDecimal tenpayAccumulate = accountPasDto.getTenpayAccumulate().subtract(multiply);
            saveFinanceRefundDto(refundVo, accountPasDto.getUuid(), accountPlatformDto.getUuid(), multiply,
                    course, description, accountPasDto.getTenpayAccumulate(), tenpayAccumulate);
            accountPasDto.setTenpayAccumulate(tenpayAccumulate);
            logger.info("订单：{} - {}", refundVo.getOrderUuid(), description);
        }
        // 1-5 退到支付宝
        map.put("course", PASSENGER_ALI_PAY);
        FinanceOrderDto aliPayFinanceOrderDto = financeOrderService.get(map).getData();
        if (aliPayFinanceOrderDto != null) {
            // - 乘客支付宝累积
//            BigDecimal multiply = aliPayFinanceOrderDto.getAmount().multiply(refundScale).setScale(1, BigDecimal.ROUND_HALF_UP);
            BigDecimal multiply = aliPayFinanceOrderDto.getAmount().multiply(refundScale).setScale(2, BigDecimal.ROUND_HALF_UP);
            BigDecimal alipayAccumulate = accountPasDto.getAlipayAccumulate().subtract(multiply);
            String description = "订单" + refundDescibe + "退款" + multiply + "元到乘客支付宝账户";
            //判断全额或者部分
            int course = refundScale.compareTo(BigDecimal.ONE) == 0 ? PLATFORM_REFUND_TO_PASSENGER_ALIPAY : PLATFORM_PART_REFUND_TO_PASSENGER_ALIPAY;
            saveFinanceRefundDto(refundVo, accountPasDto.getUuid(), accountPlatformDto.getUuid(), multiply, course, description,
                    accountPasDto.getAlipayAccumulate(), alipayAccumulate);
            accountPasDto.setAlipayAccumulate(alipayAccumulate);
            logger.info("订单：{} - {}", refundVo.getOrderUuid(), description);
        }
        ResponseData<Boolean> edit = sysAccountPassengerService.edit(accountPasDto);
        if (!edit.isSuccess() || edit.getData() == null || Objects.equals(edit.getData(), Boolean.FALSE)) {
            logger.info("订单：{} - {}", refundVo.getOrderUuid(), "退款异常");
            throw new RefundException();
        }
    }

    /**
     * 写退款流水表
     *
     * @param refundVo
     * @param financeInflow  资金流入方
     * @param financeOutflow 资金流出方
     * @param amount         退款金额
     * @param course         科目
     * @param description
     * @return
     */
    private void saveFinanceRefundDto(RefundVo refundVo, String financeInflow, String financeOutflow, BigDecimal amount,
                                      Integer course, String description, BigDecimal startBalance, BigDecimal finalBalance)
            throws RefundException {
        FinanceRefundDto financeRefundDto = new FinanceRefundDto();
        financeRefundDto.setUuid(StringUtils.buildUUID());
        financeRefundDto.setAppid(refundVo.getAppid());
        financeRefundDto.setAmount(amount);
        financeRefundDto.setBusinessUuid(refundVo.getFinanceRefundUuid());
        financeRefundDto.setCourse(course);
        financeRefundDto.setFinanceInflow(financeInflow);
        financeRefundDto.setFinanceOutflow(financeOutflow);
        financeRefundDto.setDescription(description);
        financeRefundDto.setCreateBy(ParamUtil.defaultIfNull(refundVo.getCreateBy(), refundVo.getPassengerUuid()));
        financeRefundDto.setFinanceNumber(StringUtils.buildUUID());
        financeRefundDto.setHappenTime(new Date());
        financeRefundDto.setCreateOn(new Date());
        financeRefundDto.setStartBalance(startBalance);
        financeRefundDto.setFinalBalance(finalBalance);
        ResponseData<Boolean> add = financeRefundService.add(financeRefundDto);
        if (!add.isSuccess() || add.getData() == null || Objects.equals(add.getData(), Boolean.FALSE)) {
            throw new RefundException();
        }
    }

    /**
     * 订单业务操作
     *
     * @param orderUuid
     * @param isSuccess 退款是否成功
     * @param push      是否需要推送乘客消息
     * @return
     */
    private void orderHandle(String orderUuid, Double refundFare, boolean isSuccess, boolean push) {
        OrderDto orderDto = orderService.get(orderUuid).getData();
        if (orderDto == null) {
            logger.warn("orderHandle 获取不到订单信息，orderUuid:{}", orderUuid);
            return;
        }
        //3：退款成功，2：退款中
        orderDto.setPayStatus(isSuccess ? 3 : 2);
        orderDto = OrderHelper.saveOrUpdate(orderDto);
        if (!push) {
            return;
        }
        OrderDetailDto orderDetailDto = OrderHelper.findOrderDetail(orderDto.getUuid());
        if (orderDetailDto == null) {
            logger.warn("orderHandle 获取不到订单详情信息，orderUuid:{}", orderUuid);
            return;
        }
        String deparTime = DateUtils.format(orderDetailDto.getDeparTime());
        if (isSuccess) {
            String msgContent = "您的订单已退款，退款金额：" + refundFare + "，请注意查收！欢迎再次乘坐。";
            pushRefundMsg(orderDto, msgContent, PushContent.ORDER_JOIN_REFUND_SUCCESS);
        }
        if (!isSuccess) {
            String msgContent = "您的退款请求已受理，退款金额：" + refundFare + "元，请注意查收！欢迎再次乘坐。";
            pushRefundMsg(orderDto, msgContent, PushContent.ORDER_JOIN_REFUND);
        }
    }

    /**
     * 推送退款消息
     *
     * @param
     * @return true 成功 false 失败
     */
    private Boolean pushRefundMsg(OrderDto orderDto, String msgContent, Integer pushCode) {
        PassengerVo passengerVo = passengerService.selInfo(orderDto.getPassengerUuid()).getData();
        if (passengerVo == null) {
            logger.warn("退款推送 —— 未找到该乘客：{}", orderDto.getPassengerUuid());
            return Boolean.FALSE;
        }
        Map<String, Object> map = MapUtils.build(4);
        map.put("title", "提示");
        map.put("orderUuid", orderDto.getUuid());
        //乘客消息
        if (StringUtils.isNotBlank(msgContent)) {
            map.put("content", msgContent);
            PushContent passengerPushContent = PushContent.newInstance4Dri(orderDto.getAppid(), pushCode, map);
            pushService.sendMessage(passengerVo.getUuid(), passengerPushContent);
            //短信推送
            SendMessageUtils.closeJoinOrder(passengerVo.getMobile(), msgContent, orderDto.getAppid());
            return Boolean.TRUE;
        }
        return Boolean.FALSE;
    }


    @Override
    public ResponseData<Boolean> refundQuery(String orderUuid, String userUuid) {
        List<FinanceJoinRefundDto> refundDtoList = new ArrayList<>();
        if (StringUtils.isNotEmpty(orderUuid)) {
            FinanceJoinRefundDto financeRefundDto = financeJoinRefundService.queryByOrderUuid(orderUuid).getData();
            if (financeRefundDto == null) {
                logger.warn("查询不到对应订单：{}的退款信息", orderUuid);
                return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "查询不到对应订单的退款信息");
            }
            if (FinanceJoinRefundDto.STATUS_SUCCESS == financeRefundDto.getStatus()) {
                return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "退款已成功，无需查询请求");
            }
            refundDtoList.add(financeRefundDto);
        }

        if (StringUtils.isBlank(orderUuid)) {
            Map<String, Object> params = new HashMap<>(2);
            params.put("status", FinanceJoinRefundDto.STATUS_REFUND);
            List<FinanceJoinRefundDto> list = financeJoinRefundService.list(params).getData();
            if (!CollectionUtils.isEmpty(list)) {
                refundDtoList = list;
            }
        }
        ResponseData<Boolean> responseData = ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "退款查询请求失败");
        if (CollectionUtils.isNotEmpty(refundDtoList)) {
            for (FinanceJoinRefundDto financeJoinRefundDto : refundDtoList) {
                //微信退款查询
                if (financeJoinRefundDto.getType() == OrderConstant.PAY_TYPE_TENPAY) {
                    responseData = RefundDataBuilder.buildWxRefundQueryData(financeJoinRefundDto);
                }
                //支付宝退款查询
                if (financeJoinRefundDto.getType() == OrderConstant.PAY_TYPE_ALIPAY) {
                    responseData = RefundDataBuilder.buildAliRefundQueryData(financeJoinRefundDto);
                }
                if (responseData.isSuccess() && responseData.getData() != null) {
                    //更新退款记录
                    financeJoinRefundDto.setStatus(FinanceJoinRefundDto.STATUS_SUCCESS);
                    financeJoinRefundDto.setUpdateOn(new Date());
                    financeJoinRefundDto.setUpdateBy(userUuid);
                    financeJoinRefundService.edit(financeJoinRefundDto);
                    orderHandle(financeJoinRefundDto.getOrderUuid(), financeJoinRefundDto.getMoney(), true, true);
                    return ResponseData.buildSuccessResponse("查询结果（退款成功）", true);
                }
            }
            return ResponseData.buildSuccessResponse("查询结果（退款中）", false);
        }
        return responseData;
    }
}
